package cn.com.vs.service;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;

import cn.com.vs.Configurator;
import cn.com.vs.service.domain.Member;

import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.HttpRequestWithBody;

public class IMService {
	/**
	 * 	400	invalid_grant	invalid username or password	用户名或者密码输入错误
		400	organization_application_not_found	“Could not find application for easemob-demo/aachatdemoui from URI: easemob-demo/aachatdemoui/users”	找不到aachatdemoui对应的app, 可能是URL写错了
		400	illegal_argument	“Entity user requires a property named username”	创建用户请求体未提供”username”
		400	illegal_argument	“password or pin must provided”	创建用户请求体未提供”password”
		400	json_parse	“Unexpected character (‘=’ (code 61)): was expecting a colon to separate field name and value\n at [Source: java.io.BufferedInputStream@170e3f35; line: 1, column: 23]”	发送请求时请求体不符合标准的JSON格式,服务器无法正确解析
		400	illegal_argument	“password or pin must provided”	注册用户时json中提供了password但是值未空字符
		400	duplicate_unique_property_exists	“Application 4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5Entity user requires that property named username be unique, value of dddd exists”	用户名已存在, dddd这个用户名在该app下已经存在
		400	illegal_argument	“newpassword is required”	修改用户密码的请求体没提供newpassword属性
		400	illegal_argument	“group member username1 doesn’t exist”	批量添加群组时预加入群组的新成员username不存在
		401	unauthorized	“registration is not open, please contact the app admin”	app的用户注册模式为授权注册,但是注册用户时请求头没带token
		401	auth_bad_access_token	“Unable to authenticate due to corrupt access token”	发送请求时使用的token错误, 注意:不是token过期
		401	auth_bad_access_token	“Unable to authenticate”	无效token, 符合token的格式,但是该token不是接受请求的系统生成的,系统无法识别该token
		401	 	“Unable to authenticate due to expired access token”	token过期
		404	service_resource_not_found	“Service resource not found”	URL指定的资源不存在
		500	no_full_text_index	“Entity ‘user’ with property named ‘username’ is not full text indexed. You cannot use the ‘contains’ operand on this field”	username不支持全文索引,不可以对该字段进行contains操作
		500	unsupported_service_operation	“Service operation not supported”	请求方式不被发送请求的URL支持
		500	web_application	“javax.ws.rs.WebApplicationException”
	 */

	private static Logger logger = Logger.getLogger(IMService.class);

	private static IMService inst = null;

	public static IMService getInstance(){
		return inst;
	}
	
	public static void init(){
		inst =  new IMService();
	}

	private String manager_token = null;

	private int   expireSecond = 0;

	@SuppressWarnings("unused")
	private String appID = null;

	private Thread daemonThread = null;

	private String basePath = null;
	
	protected IMService(){

		basePath = Configurator.getInstance().getString("hx_base_path");

		daemonThread = new Thread( new Runnable(){
			/**
			 * 守护线程负责更新管理员token
			 * Path : /{org_name}/{app_name}/token
			 * 	
			 *  access_token	token值
			 *	expires_in		有效时间,秒为单位, 默认是七天,在有效期内是不需要重复获取的
			 *	application		当前app的UUID值
			 */
			@Override
			public void run() {
				while(true){
					try
					{
						//初始化时或还有2小时token即将过期时做更新
						if( manager_token == null || expireSecond < 7200 ){
							JSONObject requestBody = new JSONObject();
							requestBody.put("grant_type", "client_credentials");
							requestBody.put("client_id", Configurator.getInstance().getString("hx_client_id"));
							requestBody.put("client_secret", Configurator.getInstance().getString("hx_client_secret"));
							HttpRequestWithBody req = Unirest.post(basePath+"/token");
							req.header("Content-Type","application/json");
							req.body(requestBody.toString());
							HttpResponse<JsonNode> resp = req.asJson();
							if( resp.getStatus() == HttpStatus.SC_OK ){
								JsonNode json = resp.getBody();
								JSONObject respObj = json.getObject();
								manager_token = respObj.getString("access_token");
								expireSecond = respObj.getInt("expires_in");
								appID = respObj.getString("application");
								logger.info("update huan xin manager token ok,this token will expired in "+expireSecond+" seconds");
							}else{
								logger.error("update huan xin manager token faild:"+resp.getStatusText());
							}
						}
					}catch(Exception e){
						e.printStackTrace();
						logger.error("huan xin daemon thread error:", e);
					}
					try{
						Thread.sleep(1000);
						if( expireSecond > 0 ){
							expireSecond--;
						}
					}catch(Exception e){};
				}
			}

		});
		daemonThread.setDaemon( true );
		daemonThread.start();
	}



	public boolean createIMAccount(String account,String pwd,String nickName){
		try{
			JSONObject requestBody = new JSONObject();
			requestBody.put("username", account);
			requestBody.put("password", pwd );
			requestBody.put("nickname", nickName);
			HttpRequestWithBody req = Unirest.post(basePath+"/users");
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			req.body(requestBody.toString());
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("createIMAccount faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("create account exception:",e);
		}
		return false;
	}
	
	public boolean deleteIMAccount(String account){
		try{
			HttpRequestWithBody req = Unirest.delete(basePath+"/users/"+account);
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("deleteIMAccount faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("deleteIMAccount account exception:",e);
		}
		return false;
	}
	
	public boolean addFriend( String whosfriend,String friend ){
		try{
			HttpRequestWithBody req = Unirest.post(basePath+"/users/"+whosfriend+"/contacts/users/"+friend);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("addFriend faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("addFriend exception:",e);
		}
		return false;
	}
	
	public boolean delFriend( String whosfriend,String friend ){
		try{
			HttpRequestWithBody req = Unirest.delete(basePath+"/users/"+whosfriend+"/contacts/users/"+friend);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("delFriend faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("delFriend exception:",e);
		}
		return false;
	}

	public boolean updateNickName( String who,String nickName ){
		return true;
		/*
		try{
			JSONObject requestBody = new JSONObject();
			requestBody.put("nickname", nickName);
			HttpRequestWithBody req = Unirest.put(basePath+"/users/"+who);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			req.body( requestBody.toString() );
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("updateNickName faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("updateNickName exception:",e);
		}
		return false;
		*/
	}
	
	public String createChatGroup(String name,String desc,
			boolean isPublic,int maxUsers,boolean approval,
			String owner,List<Member> members){
		try{
			JSONObject requestBody = new JSONObject();
			requestBody.put("groupname", name);
			requestBody.put("desc", StringUtils.isEmpty(desc)?"":desc);
			requestBody.put("public", isPublic);
			requestBody.put("maxusers", maxUsers);
			requestBody.put("approval", approval);
			requestBody.put("owner", owner);
			if( members != null && !members.isEmpty() ){
				JSONArray array = new JSONArray();
				for( Member member : members ){
					array.put( member.getAccount() );
				}
				requestBody.put("members", array);
			}
			HttpRequestWithBody req = Unirest.post(basePath+"/chatgroups");
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			req.body( requestBody.toString() );
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				JSONObject respObj = resp.getBody().getObject();
				Object obj = respObj.get("data");
				if( obj != null && obj instanceof JSONObject ){
					JSONObject groupInfo = (JSONObject)obj;
					return groupInfo.getString("groupid");
				}
			}else{
				checkToken(resp);
				logger.error("createChatGroup faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("createChatGroup exception:",e);
		}
		return null;
	}
	
	public boolean deleteChatGroup(String groupID){
		try{
			HttpRequestWithBody req = Unirest.delete(basePath+"/chatgroups/"+groupID);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("deleteChatGroup faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("deleteChatGroup exception:",e);
		}
		return false;
	}
	
	public boolean joinGroup(String groupID,String userAccount){
		try{
			HttpRequestWithBody req = Unirest.post(basePath+"/chatgroups/"+groupID+"/users/"+userAccount);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("createChatGroup faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("createChatGroup exception:",e);
		}
		return false;
	}
	
	public boolean remove(String groupID,String userAccount){
		try{
			HttpRequestWithBody req = Unirest.delete(basePath+"/chatgroups/"+groupID+"/users/"+userAccount);
			req.header("Content-Type","application/json");
			req.header("Authorization","Bearer "+manager_token);
			HttpResponse<JsonNode> resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				return true;
			}else{
				checkToken(resp);
				logger.error("createChatGroup faild:status="+resp.getStatus()+" msg="+resp.getStatusText());
			}
		}catch(Exception e){
			logger.error("createChatGroup exception:",e);
		}
		return false;
	}

	public static void main(String[] args) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException{
		JSONObject requestBody = new JSONObject();
		requestBody.put("grant_type", "client_credentials");
		requestBody.put("client_id", "YXA6tWoqQGsQEeS9clnJUJY4_A");
		requestBody.put("client_secret","YXA6ht3AOihkDIRV1d8eTlUxoPJVXPY");
		HttpRequestWithBody req = Unirest.post( "https://a1.easemob.com/windstear/test/token" );
		req.header("Content-Type","application/json");
		req.body(requestBody.toString());
		HttpResponse<JsonNode> resp;
		try {
			resp = req.asJson();
			if( resp.getStatus() == HttpStatus.SC_OK ){
				logger.info("update huan xin manager token ok,this token will expired in "+100+" seconds");
			}else{
				logger.error("update huan xin manager token faild:"+resp.getStatusText());
			}
		} catch (UnirestException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}

	}

	private void checkToken(HttpResponse<?> resp){
		if( resp.getStatus() == HttpStatus.SC_UNAUTHORIZED && 
				resp.getStatusText().indexOf("expired") != -1 ){
			manager_token = null;
		}
	}
}
